﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using MvcEngine.Mvc.Filters;
using MvcEngine.Mvc.Results;
using MvcEngine.Mvc.Models.ViewModels;
using MvcEngine.Core.Helpers;
using MvcEngine.Core;
using MvcEngine.Core.Registry;
using MvcEngine.Mvc.Extensions;
using MvcEngine.Mvc.Models;

namespace MvcEngine.Mvc.Infrastructure
{
    public class MvcEngineControllerActionInvoker : ControllerActionInvoker
    {
        private IActionFilterRegistry registry;

        public MvcEngineControllerActionInvoker(IActionFilterRegistry registry)
        {
            this.registry = registry;
        }



        //public override bool InvokeAction(ControllerContext controllerContext, string actionName)
        //{
        //    Guard.ThrowIfNull(controllerContext);

        //    //string moduleName = ModuleManager.Current.GetModuleName(controllerContext.Controller.GetType().Assembly.GetName().Name);

        //    //System.Web.HttpContext.Current.Items["CurrentModule"] = moduleName;

        //    if (string.IsNullOrEmpty(actionName))
        //    {
        //        //throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
        //    }
        //    ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
        //    ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName);
        //    if (actionDescriptor == null)
        //    {
        //        return false;
        //    }
        //    FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor);
        //    try
        //    {
        //        AuthorizationContext context = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);
        //        if (context.Result != null)
        //        {
        //            this.InvokeActionResult(controllerContext, context.Result);
        //        }
        //        else
        //        {
        //            if (controllerContext.Controller.ValidateRequest)
        //            {
        //                controllerContext.HttpContext.Request.ValidateInput();
        //            }
        //            IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor);
        //            ActionExecutedContext context2 = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);
        //            this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, context2.Result);
        //        }
        //    }
        //    catch (System.Threading.ThreadAbortException)
        //    {
        //        throw;
        //    }
        //    catch (Exception exception)
        //    {
        //        ExceptionContext context3 = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception);
        //        if (!context3.ExceptionHandled)
        //        {
        //            throw;
        //        }
        //        this.InvokeActionResult(controllerContext, context3.Result);
        //    }
        //    return true;

        //}

        protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            FilterInfo filters = base.GetFilters(controllerContext, actionDescriptor);

            FilterInfo registeredFilters = registry.GetFilters(new ActionFilterRegistryContext(controllerContext, actionDescriptor));

            foreach (IActionFilter actionFilter in registeredFilters.ActionFilters)
                filters.ActionFilters.Add(actionFilter);
            foreach (IAuthorizationFilter authorizationFilter in registeredFilters.AuthorizationFilters)
                filters.AuthorizationFilters.Add(authorizationFilter);
            foreach (IExceptionFilter exceptionFilter in registeredFilters.ExceptionFilters)
                filters.ExceptionFilters.Add(exceptionFilter);
            foreach (IResultFilter resultFilter in registeredFilters.ResultFilters)
                filters.ResultFilters.Add(resultFilter);

            return filters;
        }



        protected override ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
        {
            if (actionReturnValue == null)
            {
                return new NotFoundResult();
            }

            if (typeof(ActionResult).IsAssignableFrom(actionReturnValue.GetType()))
                return actionReturnValue as ActionResult;

            controllerContext.Controller.ViewData.Model = actionReturnValue;

            Type type = actionReturnValue.GetType();
            foreach (var item in type.GetProperties())
            {
                var attributes = item.GetCustomAttributes(false);
                var dropDownAttribute = attributes.OfType<DropDownListAttribute>().FirstOrDefault();
                if (dropDownAttribute != null)
                {
                    var property = type.GetProperty(dropDownAttribute.ViewDataKey);
                    if (property != null)
                    {
                        controllerContext.Controller.ViewData[dropDownAttribute.ViewDataKey] = property.GetValue(actionReturnValue, null);
                    }
                }
            }

            if (typeof(MvcEngineModel).IsAssignableFrom(actionReturnValue.GetType()))
            {
                MvcEngineModel modelItem = actionReturnValue as MvcEngineModel;
                if (modelItem != null && !string.IsNullOrEmpty(modelItem.ViewName))
                {
                    return new ViewResult()
                    {
                        ViewData = controllerContext.Controller.ViewData,
                        TempData = controllerContext.Controller.TempData,
                        ViewName = modelItem.ViewName
                    };
                }
            }

            return new ViewResult()
            {
                ViewData = controllerContext.Controller.ViewData,
                TempData = controllerContext.Controller.TempData
            };
        }
    }
}
